import {Tool} from '../common/tool.js';

/**
 * the predict table maps non-terminal symbols and input tokens to specific 
 * production rules in the grammar. It is used by the parser to determine 
 * which production rule to apply based on the current non-terminal symbol 
 * and the lookahead token in the input stream. Each entry in the table 
 * represents a valid combination of a non-terminal and a terminal, pointing 
 * to the appropriate production that should be applied in the parsing process.
 */
function predictTable(grammars){
    const table = {};
    grammars.grammars.forEach(grammar=>grammar.productions().forEach(production=>{
        //if production is epsilon, all follow of the grammar will target the epsilon production
        if(production.isEmpty()){
            grammar.follow().forEach(teminal=>mapping(grammar,production,teminal));   
        }    
        production.first().forEach(teminal=>mapping(grammar,production,teminal));
    }));

    function mapping( grammar, production, teminal) {
        const g = grammar.name();//grammar name for table key
        const t = terminal.name();//terminal name for table key
        let productions = table[t];
        if(productions===undefined){
            productions = {};
            table[t] = productions;
        }
        productions[grammar] = production;
    }

    return {
        match: (token, grammar, line)=> {
            const terminal = token.terminal();
            const productions = table[terminal];
            if (productions === undefined) {
                Tool.grammarError(`${terminal.text()} is not found in predict table\n ${line}`);
            }
            const production = productions[grammar.name()];
            if (production === undefined) {
                Tool.grammarError(`token: ${terminal.name()} : ${token.lexeme()} doesn't match any outline grammar definition at line: 
                    ${token.line()}, position from ${token.start()} to ${token.end()}\n${line}`);
            }
            return production;
        }
    }
}

export {predictTable};